home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 11 / CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso / www / http / www.amigasupport.com / software / arc / aiff_dtc.lha / source / Class.c < prev    next >
C/C++ Source or Header  |  1995-01-12  |  16KB  |  729 lines

  1. /*
  2. **    AIFF DataType
  3. **
  4. **    Written by Olaf `Olsen' Barthel <olsen@sourcery.han.de>
  5. **        Public domain
  6. **
  7. ** :ts=4
  8. */
  9.  
  10. #include "Data.h"
  11.  
  12.     // Maximum supported replay rate, as per the "Amiga Hardware Reference Manual"
  13.  
  14. #define MAX_SAMPLE_RATE 28867
  15.  
  16.     // The minimum sample rate we will allow when scaling a sound down
  17.  
  18. #define MIN_SAMPLE_RATE 5563
  19.  
  20.     // How many bytes to read in one piece
  21.  
  22. #define MIN_FRAME_RATE    (2048 * 8)
  23.  
  24.     // 80 bit IEEE Standard 754 floating point number
  25.  
  26. typedef struct {
  27.     unsigned short    exponent;            // Exponent, bit #15 is sign bit for mantissa
  28.     unsigned long    mantissa[2];        // 64 bit mantissa
  29. } extended;
  30.  
  31.     // Audio Interchange Format chunk data
  32.  
  33. #define ID_AIFF MAKE_ID('A','I','F','F')
  34. #define ID_AIFC MAKE_ID('A','I','F','C')
  35.  
  36. #define ID_FVER MAKE_ID('F','V','E','R')
  37. #define ID_COMM MAKE_ID('C','O','M','M')
  38. #define ID_SSND MAKE_ID('S','S','N','D')
  39.  
  40.     // "COMM" chunk header
  41.  
  42. typedef struct {
  43.     short            numChannels;        // Number of channels
  44.     unsigned long    numSampleFrames;    // Number of sample frames
  45.     short            sampleSize;         // Number of bits per sample point
  46.     extended        sampleRate;         // Replay rate in samples per second
  47. } CommonChunk;
  48.  
  49.     // The same for "AIFC" type files; this should be longer, but we don't
  50.     // need the name of the compression format
  51.  
  52. typedef struct {
  53.     short            numChannels;        // Number of channels
  54.     unsigned long    numSampleFrames;    // Number of sample frames
  55.     short            sampleSize;         // Number of bits per sample point
  56.     extended        sampleRate;         // Replay rate in samples per second
  57.     unsigned long    compressionType;    // Compression type
  58. } ExtCommonChunk;
  59.  
  60. #define NO_COMPRESSION MAKE_ID('N','O','N','E') // No sound compression
  61.  
  62.     // "SSND" chunk header
  63.  
  64. typedef struct {
  65.     unsigned long    offset,             // Offset to sound data, for block alignment
  66.                     blockSize;            // Size of block data is aligned to
  67. } SampledSoundHeader;
  68.  
  69.     // "FVER" chunk header
  70.  
  71. typedef struct {
  72.     long            timestamp;            // Format version creation date
  73. } FormatVersionHeader;
  74.  
  75. #define AIFCVersion1 0xA2805140         // "AIFC" file format version #1
  76.  
  77.     /* In StackCall.asm */
  78.  
  79. LONG __stdargs StackCall(LONG *Success,LONG StackSize,LONG ArgCount,LONG (* __stdargs Function)(...),...);
  80.  
  81.     /* extended2long(const extended *ex):
  82.      *
  83.      *    Convert an 80 bit IEEE Standard 754 floating point number
  84.      *    into an integer value.
  85.      */
  86.  
  87. STATIC long __regargs
  88. extended2long(const extended *ex)
  89. {
  90.     unsigned long    mantissa = ex -> mantissa[0];    // We only need 32 bits precision
  91.     long            exponent = ex -> exponent,
  92.                     sign;
  93.  
  94.         // Is the mantissa positive or negative?
  95.  
  96.     if(exponent & 0x8000)
  97.         sign = -1;
  98.     else
  99.         sign =    1;
  100.  
  101.         // Unbias the exponent
  102.  
  103.     exponent = (exponent & 0x7FFF) - 0x3FFF;
  104.  
  105.         // If the exponent is negative, set the mantissa to zero
  106.  
  107.     if(exponent < 0)
  108.         mantissa = 0;
  109.     else
  110.     {
  111.             // Special meaning?
  112.  
  113.         exponent -= 31;
  114.  
  115.             // Overflow?
  116.  
  117.         if(exponent > 0)
  118.             mantissa = 0x7FFFFFFF;
  119.         else
  120.             mantissa >>= -exponent; // Let the point float...
  121.     }
  122.  
  123.         // That's all...
  124.  
  125.     return(sign * (long)mantissa);
  126. }
  127.  
  128.     /* CloseIFFStream(struct IFFHandle *Handle,struct ClassBase *ClassBase):
  129.      *
  130.      *    Close an IFFHandle and clean up the associated data.
  131.      */
  132.  
  133. STATIC VOID __regargs
  134. CloseIFFStream(struct IFFHandle *Handle,struct ClassBase *ClassBase)
  135. {
  136.     CloseIFF(Handle);
  137.  
  138.     CloseAsync((AsyncFile *)Handle -> iff_Stream);
  139.  
  140.     FreeIFF(Handle);
  141. }
  142.  
  143.     /* OpenIFFStream(STRPTR Name,LONG *Error,struct ClassBase *ClassBase):
  144.      *
  145.      *    Open an IFF file for reading.
  146.      */
  147.  
  148. STATIC struct IFFHandle * __regargs
  149. OpenIFFStream(STRPTR Name,LONG *Error,struct ClassBase *ClassBase)
  150. {
  151.     struct IFFHandle *Handle;
  152.  
  153.     *Error = 0;
  154.  
  155.     if(Handle = AllocIFF())
  156.     {
  157.         if(Handle -> iff_Stream = (ULONG)OpenAsync(Name,MODE_READ,MIN_FRAME_RATE,SysBase,DOSBase))
  158.         {
  159.             InitIFF(Handle,IFFF_FSEEK | IFFF_RSEEK,&AsyncHook);
  160.  
  161.             if(!(*Error = OpenIFF(Handle,IFFF_READ)))
  162.                 return(Handle);
  163.             else
  164.                 CloseAsync((AsyncFile *)Handle -> iff_Stream);
  165.         }
  166.  
  167.         FreeIFF(Handle);
  168.     }
  169.     else
  170.         *Error = ERROR_NO_FREE_STORE;
  171.  
  172.     return(NULL);
  173. }
  174.  
  175.     /* Flatten():
  176.      *
  177.      *    Flatten the "AIFF"/"AIFC" sound data, i.e. blend all the channels
  178.      *    into a single monophonic chunk and crop the data to eight bits per
  179.      *    sample.
  180.      */
  181.  
  182. STATIC VOID __regargs
  183. Flatten(const UBYTE *Src,BYTE *Dst,const LONG BytesPerPoint,const LONG NumChannels,LONG NumFrames,const LONG Skip)
  184. {
  185.     LONG Sum,Value,SkipCount,i;
  186.  
  187.         // Make sure that the first sample is converted
  188.  
  189.     SkipCount = 1;
  190.  
  191.         // Convert all the frames if possible
  192.  
  193.     while(NumFrames-- > 0)
  194.     {
  195.             // Add up the channel data
  196.  
  197.         for(i = Sum = 0 ; i < NumChannels ; i++)
  198.         {
  199.                 // The audio data is always left adjusted,
  200.                 // which makes it rather easy to convert it
  201.                 // to eight bits per sample
  202.  
  203.             switch(BytesPerPoint)
  204.             {
  205.                 case 1:
  206.  
  207.                     Value = (ULONG)Src[0] << 24;
  208.                     break;
  209.  
  210.                 case 2:
  211.  
  212.                     Value = ((ULONG)Src[0] << 24) | ((ULONG)Src[1] << 16);
  213.                     break;
  214.  
  215.                 case 3:
  216.  
  217.                     Value = ((ULONG)Src[0] << 24) | ((ULONG)Src[1] << 16) | ((ULONG)Src[2] << 8);
  218.                     break;
  219.  
  220.                 case 4:
  221.  
  222.                     Value = ((ULONG)Src[0] << 24) | ((ULONG)Src[1] << 16) | ((ULONG)Src[2] << 8) | ((ULONG)Src[3]);
  223.                     break;
  224.             }
  225.  
  226.                 // Skip to the next sample
  227.  
  228.             Src += BytesPerPoint;
  229.  
  230.                 // Add the new sample, 16 bits only
  231.  
  232.             Sum += (Value >> 8);
  233.         }
  234.  
  235.             // Store this sample value?
  236.  
  237.         if(--SkipCount < 1)
  238.         {
  239.                 // Calculate the monophonic sample data and
  240.                 // crop it to eight bits
  241.  
  242.             Sum = (Sum / NumChannels) >> 16;
  243.  
  244.                 // Make sure that the value is in range
  245.  
  246.             if(Sum < -128)
  247.                 Sum = -128;
  248.             else
  249.             {
  250.                 if(Sum > 127)
  251.                     Sum = 127;
  252.             }
  253.  
  254.                 // Keep this sample
  255.  
  256.             *Dst++ = (BYTE)Sum;
  257.  
  258.                 // Skip the next samples if necessary
  259.  
  260.             SkipCount = Skip;
  261.         }
  262.     }
  263. }
  264.  
  265.     /* ConvertAIFF():
  266.      *
  267.      *    Convert "AIFF"/"AIFC" audio data into plain 8 bit audio data.
  268.      */
  269.  
  270. STATIC BOOL
  271. ConvertAIFF(struct IFFHandle *IFFHandle,BYTE **DstPtr,struct VoiceHeader *VoiceHeader,const ULONG MemFlags,LONG *Error,struct ClassBase *ClassBase)
  272. {
  273.     STATIC LONG Stops[] =
  274.     {
  275.         ID_AIFF,ID_COMM,    // AIFF chunks
  276.         ID_AIFF,ID_SSND,
  277.  
  278.         ID_AIFC,ID_FVER,    // AIFC chunks
  279.         ID_AIFC,ID_COMM,
  280.         ID_AIFC,ID_SSND
  281.     };
  282.  
  283.     ExtCommonChunk         Common;
  284.     LONG                 SrcBufferSize,
  285.                          SrcFrames,
  286.                          DstFrames,
  287.                          DstRate,
  288.                          DstSkip,
  289.                          Size;
  290.     FormatVersionHeader  FormatHeader;
  291.     SampledSoundHeader     SampleHeader;
  292.     UBYTE                *SrcBuffer    = NULL;
  293.     BYTE                *DstBuffer    = NULL;
  294.     BOOL                 Result     = FALSE;
  295.  
  296.         // There are only two/three mandatory chunks to look for
  297.  
  298.     if(!(*Error = StopChunks(IFFHandle,Stops,5)))
  299.     {
  300.         struct ContextNode    *Chunk;
  301.         LONG                 BytesPerPoint;
  302.  
  303.         while(!Result && !(*Error) && !ParseIFF(IFFHandle,IFFPARSE_SCAN))
  304.         {
  305.             Chunk = CurrentChunk(IFFHandle);
  306.  
  307.             switch(Chunk -> cn_ID)
  308.             {
  309.                     // This is the file format version ID
  310.  
  311.                 case ID_FVER:
  312.  
  313.                     if(ReadChunkBytes(IFFHandle,&FormatHeader,sizeof(FormatVersionHeader)) != sizeof(FormatVersionHeader))
  314.                     {
  315.                         *Error = IFFERR_READ;
  316.  
  317.                         break;
  318.                     }
  319.  
  320.                         // Does this reader support this format?
  321.  
  322.                     if(FormatHeader . timestamp != AIFCVersion1)
  323.                     {
  324.                         *Error = ERROR_NOT_IMPLEMENTED;
  325.  
  326.                         break;
  327.                     }
  328.  
  329.                     break;
  330.  
  331.                     // This chunk is common for all "AIFF" variants
  332.  
  333.                 case ID_COMM:
  334.  
  335.                         // Determine how many bytes to read
  336.  
  337.                     if(Chunk -> cn_Type == ID_AIFF)
  338.                         Size = sizeof(CommonChunk);
  339.                     else
  340.                         Size = sizeof(ExtCommonChunk);
  341.  
  342.                     if(ReadChunkBytes(IFFHandle,&Common,Size) != Size)
  343.                     {
  344.                         *Error = IFFERR_READ;
  345.  
  346.                         break;
  347.                     }
  348.  
  349.                         // Is this a compressed "AIFC" file?
  350.  
  351.                     if(Chunk -> cn_Type == ID_AIFC && Common . compressionType != NO_COMPRESSION)
  352.                     {
  353.                         *Error = DTERROR_UNKNOWN_COMPRESSION;
  354.  
  355.                         break;
  356.                     }
  357.  
  358.                         // Keep the basic data
  359.  
  360.                     DstFrames    = Common . numSampleFrames;
  361.                     DstRate     = extended2long(&Common . sampleRate);
  362.                     DstSkip     = 1;
  363.  
  364.                         // The current Amiga audio hardware has a fixed
  365.                         // replay speed limit. We will compensate for it
  366.                         // by cropping the audio data if necessary.
  367.  
  368.                     while(DstRate > MAX_SAMPLE_RATE)
  369.                     {
  370.                         DstFrames = (DstFrames + 1) / 2;
  371.  
  372.                         DstRate     /= 2;
  373.                         DstSkip     *= 2;
  374.                     }
  375.  
  376.                         // See how many bytes make up one sample point
  377.  
  378.                     if(Common . sampleSize <= 8)
  379.                         BytesPerPoint = 1;
  380.                     else
  381.                     {
  382.                         if(Common . sampleSize <= 16)
  383.                             BytesPerPoint = 2;
  384.                         else
  385.                         {
  386.                             if(Common . sampleSize <= 24)
  387.                                 BytesPerPoint = 3;
  388.                             else
  389.                                 BytesPerPoint = 4;
  390.                         }
  391.                     }
  392.  
  393.                         // Just to be sure we accept multiple "COMM" chunks
  394.  
  395.                     if(SrcBuffer)
  396.                         FreeVec(SrcBuffer);
  397.  
  398.                     if(DstBuffer)
  399.                     {
  400.                         FreeVec(DstBuffer);
  401.  
  402.                         DstBuffer = NULL;
  403.                     }
  404.  
  405.                         // Don't waste too much memory for loading
  406.  
  407.                     if(Common . numSampleFrames < MIN_FRAME_RATE)
  408.                         SrcFrames = Common . numSampleFrames;
  409.                     else
  410.                         SrcFrames = MIN_FRAME_RATE;
  411.  
  412.                         // Allocate the decoding buffer
  413.  
  414.                     if(!(SrcBuffer = AllocVec(SrcBufferSize = BytesPerPoint * Common . numChannels * SrcFrames,MEMF_ANY)))
  415.                     {
  416.                         *Error = ERROR_NO_FREE_STORE;
  417.  
  418.                         break;
  419.                     }
  420.  
  421.                         // Step down in size in order to make the allocation fit
  422.  
  423.                     while(DstRate > MIN_SAMPLE_RATE && DstFrames > 0 && !(DstBuffer = AllocVec(DstFrames,MemFlags | MEMF_CLEAR)))
  424.                     {
  425.                         DstFrames = (DstFrames + 1) / 2;
  426.  
  427.                         DstRate     /= 2;
  428.                         DstSkip     *= 2;
  429.                     }
  430.  
  431.                         // Any success?
  432.  
  433.                     if(!DstBuffer)
  434.                         *Error = ERROR_NO_FREE_STORE;
  435.  
  436.                     break;
  437.  
  438.                     // Here follows the sampled sound; this chunk is somewhat
  439.                     // equivalent to the "8SVX"/"BODY" chunk.
  440.  
  441.                 case ID_SSND:
  442.  
  443.                         // Read the data header
  444.  
  445.                     if(ReadChunkBytes(IFFHandle,&SampleHeader,sizeof(SampledSoundHeader)) != sizeof(SampledSoundHeader))
  446.                         *Error = IFFERR_READ;
  447.                     else
  448.                     {
  449.                             // Is the data block aligned?
  450.  
  451.                         if(SampleHeader . offset)
  452.                         {
  453.                             LONG Needed = SampleHeader . offset,Skip;
  454.  
  455.                                 // Skip the padding data
  456.  
  457.                             while(!(*Error) && Needed > 0)
  458.                             {
  459.                                 if(SrcBufferSize > Needed)
  460.                                     Skip = Needed;
  461.                                 else
  462.                                     Skip = SrcBufferSize;
  463.  
  464.                                 if(ReadChunkBytes(IFFHandle,SrcBuffer,Skip) == Skip)
  465.                                     Needed -= Skip;
  466.                                 else
  467.                                     *Error = IFFERR_READ;
  468.                             }
  469.                         }
  470.  
  471.                         if(!(*Error))
  472.                         {
  473.                             LONG    TotalFrames = Common . numSampleFrames,
  474.                                     FrameSize    = BytesPerPoint * Common . numChannels,
  475.                                     Frames;
  476.  
  477.                                 // Initialize the voice header
  478.  
  479.                             memset(VoiceHeader,0,sizeof(struct VoiceHeader));
  480.  
  481.                             VoiceHeader -> vh_OneShotHiSamples    = DstFrames;
  482.                             VoiceHeader -> vh_SamplesPerSec     = DstRate;
  483.                             VoiceHeader -> vh_Octaves            = 1;
  484.                             VoiceHeader -> vh_Compression        = CMP_NONE;
  485.                             VoiceHeader -> vh_Volume            = 64;
  486.  
  487.                             *DstPtr = DstBuffer;
  488.  
  489.                             if(!(*Error))
  490.                             {
  491.                                 BYTE    *Dst = DstBuffer,Smallest,Largest;
  492.                                 ULONG     i;
  493.  
  494.                                     // Read the audio data frame by frame
  495.  
  496.                                 while(!(*Error) && TotalFrames > 0)
  497.                                 {
  498.                                     if(SrcFrames > TotalFrames)
  499.                                         Frames = TotalFrames;
  500.                                     else
  501.                                         Frames = SrcFrames;
  502.  
  503.                                     if(ReadChunkRecords(IFFHandle,SrcBuffer,FrameSize,Frames) == Frames)
  504.                                     {
  505.                                         Flatten(SrcBuffer,Dst,BytesPerPoint,Common . numChannels,Frames,DstSkip);
  506.  
  507.                                         Dst += Frames / DstSkip;
  508.  
  509.                                         TotalFrames -= Frames;
  510.                                     }
  511.                                     else
  512.                                         *Error = IFFERR_READ;
  513.                                 }
  514.  
  515.                                     // Look for the smallest and the largest
  516.                                     // sample value
  517.  
  518.                                 Smallest    = 127;
  519.                                 Largest     = -128;
  520.  
  521.                                 for(i = 0 ; i < DstFrames ; i++)
  522.                                 {
  523.                                     if(DstBuffer[i] < Smallest)
  524.                                         Smallest = DstBuffer[i];
  525.  
  526.                                     if(DstBuffer[i] > Largest)
  527.                                         Largest = DstBuffer[i];
  528.                                 }
  529.  
  530.                                     // Does it use the full range?
  531.  
  532.                                 if(Smallest > -128 || Largest < 127)
  533.                                 {
  534.                                     BYTE    Table[256],*Index;
  535.                                     WORD    j;
  536.  
  537.                                         // Point it into the middle
  538.  
  539.                                     Index = &Table[128];
  540.  
  541.                                         // Scale the negative values
  542.                                         // to use the full dynamic
  543.                                         // amplitude range
  544.  
  545.                                     for(j = Smallest ; j < 0 ; j++)
  546.                                         Index[j] = (-128 * j) / Smallest;
  547.  
  548.                                         // Cut off anything below the
  549.                                         // smallest value
  550.  
  551.                                     for(j = -128 ; j < Smallest ; j++)
  552.                                         Index[j] = -128;
  553.  
  554.                                     Index[0] = 0;
  555.  
  556.                                         // Scale the positive values
  557.                                         // to use the full dynamic
  558.                                         // amplitude range
  559.  
  560.                                     for(j = 1 ; j <= Largest ; j++)
  561.                                         Index[j] = (127 * j) / Largest;
  562.  
  563.                                         // Cut off anything above the
  564.                                         // largest value
  565.  
  566.                                     for(j = Largest + 1 ; j < 256 ; j++)
  567.                                         Index[j] = 127;
  568.  
  569.                                         // Make the data use the full range
  570.  
  571.                                     for(i = 0 ; i < DstFrames ; i++)
  572.                                         DstBuffer[i] = Index[DstBuffer[i]];
  573.                                 }
  574.  
  575.                                 Result = TRUE;
  576.                             }
  577.                         }
  578.                     }
  579.  
  580.                     break;
  581.             }
  582.         }
  583.     }
  584.  
  585.         // Clean up...
  586.  
  587.     if(SrcBuffer)
  588.         FreeVec(SrcBuffer);
  589.  
  590.     if(DstBuffer && (*Error || !Result))
  591.         FreeVec(DstBuffer);
  592.  
  593.     if(*Error)
  594.         Result = FALSE;
  595.  
  596.     return(Result);
  597. }
  598.  
  599.     /* GetAIFF(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase):
  600.      *
  601.      *    Create a datatypes object from an "AIFF"/"AIFC" file suitable for
  602.      *    MultiView, etc. to display or replay.
  603.      */
  604.  
  605. STATIC BOOL __regargs
  606. GetAIFF(Object *object,struct TagItem *Tags,struct ClassBase *ClassBase)
  607. {
  608.     struct VoiceHeader    *VoiceHeader    = NULL;
  609.     BPTR                 File            = NULL;
  610.     LONG                 Error            = 0;
  611.     STRPTR                 Title            = (STRPTR)GetTagData(DTA_Name,NULL,Tags);
  612.     BOOL                 Result         = FALSE;
  613.  
  614.         // Get the basic data
  615.  
  616.     GetDTAttrs(object,
  617.         SDTA_VoiceHeader,    &VoiceHeader,
  618.         DTA_Handle,         &File,
  619.     TAG_DONE);
  620.  
  621.         // Do we have everything we need?
  622.  
  623.     if(File && VoiceHeader && Title)
  624.     {
  625.         struct IFFHandle *Handle;
  626.  
  627.             // Open the IFF file for reading
  628.  
  629.         if(Handle = OpenIFFStream(Title,&Error,ClassBase))
  630.         {
  631.             BYTE    *Sample;
  632.             ULONG     Memory;
  633.  
  634.                 // sound.datatype v40 no longer requires
  635.                 // the entire sample to reside in chip memory
  636.  
  637.             if(SuperClassBase -> lib_Version > 39)
  638.                 Memory = MEMF_ANY;
  639.             else
  640.                 Memory = MEMF_CHIP;
  641.  
  642.                 // Convert the audio file
  643.  
  644.             if(ConvertAIFF(Handle,&Sample,VoiceHeader,Memory,&Error,ClassBase))
  645.             {
  646.                     // Fill in the remaining information
  647.  
  648.                 SetDTAttrs(object,NULL,NULL,
  649.                     DTA_ObjName,        Title,
  650.                     SDTA_Sample,        Sample,
  651.                     SDTA_SampleLength,    VoiceHeader -> vh_OneShotHiSamples,
  652.                     SDTA_Period,        (ULONG)(SysBase -> ex_EClockFrequency * 5) / (ULONG)VoiceHeader -> vh_SamplesPerSec,
  653.                     SDTA_Volume,        64,
  654.                     SDTA_Cycles,        1,
  655.                 TAG_DONE);
  656.  
  657.                 Result = TRUE;
  658.             }
  659.  
  660.                 // Clean up
  661.  
  662.             CloseIFFStream(Handle,ClassBase);
  663.         }
  664.     }
  665.     else
  666.         Error = ERROR_OBJECT_NOT_FOUND;
  667.  
  668.     if(Error)
  669.         SetIoErr(Error);
  670.  
  671.     return(Result);
  672. }
  673.  
  674.     /* ClassDispatch():
  675.      *
  676.      *    The class dispatcher routine.
  677.      */
  678.  
  679. STATIC Object * __stdargs
  680. RealClassDispatch(Class *class,Object *object,Msg msg)
  681. {
  682.     struct ClassBase    *ClassBase = (struct ClassBase *)class -> cl_UserData;
  683.     Object                *Result;
  684.  
  685.         // What message is it?
  686.  
  687.     switch(msg -> MethodID)
  688.     {
  689.             // Create a new instance
  690.  
  691.         case OM_NEW:
  692.  
  693.             if(Result = (Object *)DoSuperMethodA(class,object,msg))
  694.             {
  695.                 if(!GetAIFF(Result,((struct opSet *)msg) -> ops_AttrList,ClassBase))
  696.                 {
  697.                     CoerceMethod(class,Result,OM_DISPOSE);
  698.  
  699.                     Result = NULL;
  700.                 }
  701.             }
  702.  
  703.             break;
  704.  
  705.             // Let the superclass handle the rest
  706.  
  707.         default:
  708.  
  709.             Result = (Object *)DoSuperMethodA(class,object,msg);
  710.  
  711.             break;
  712.     }
  713.  
  714.     return(Result);
  715. }
  716.  
  717.     /* ClassDispatch():
  718.      *
  719.      *    The frontend to the real class dispatcher routine.
  720.      */
  721.  
  722. Object * __saveds __asm
  723. ClassDispatch(register __a0 Class *class,register __a2 Object *object,register __a1 Msg msg)
  724. {
  725.     LONG Success;
  726.  
  727.     return((Object *)StackCall(&Success,8192,3,(LONG (* __stdargs)(...))RealClassDispatch,class,object,msg));
  728. }
  729.